package edu.ucsf.mousedatabase.servlets; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.*; import static edu.ucsf.mousedatabase.HTMLGeneration.*; import java.io.IOException; import java.io.StringReader; import java.security.AccessControlException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import com.itextpdf.text.*; import com.itextpdf.text.Font.FontFamily; import com.itextpdf.text.html.simpleparser.HTMLWorker; import com.itextpdf.text.pdf.PdfPCell; import com.itextpdf.text.pdf.PdfPTable; import com.itextpdf.text.pdf.PdfWriter; import edu.ucsf.mousedatabase.DBConnect; import edu.ucsf.mousedatabase.HTMLUtilities; import edu.ucsf.mousedatabase.Log; import edu.ucsf.mousedatabase.objects.Facility; import edu.ucsf.mousedatabase.objects.Gene; import edu.ucsf.mousedatabase.objects.Holder; import edu.ucsf.mousedatabase.objects.MouseHolder; import edu.ucsf.mousedatabase.objects.MouseRecord; import edu.ucsf.mousedatabase.objects.MouseType; public class PdfServlet extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; private static Font FONT_NORMAL, FONT_BOLD, FONT_MOUSENAME, FONT_TITLE; private static Chunk NL; private String documentName = DBConnect.loadSetting("general_site_name").value; static { FONT_NORMAL = new Font(FontFamily.HELVETICA); FONT_NORMAL.setSize(10); FONT_BOLD = new Font(FONT_NORMAL); FONT_BOLD.setStyle(Font.BOLD); FONT_MOUSENAME = new Font(FONT_BOLD); FONT_TITLE = new Font(FONT_BOLD); FONT_TITLE.setSize(16); NL = Chunk.NEWLINE; } protected void doGet( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { Element data = getMouseListPdf(request); ServletOutputStream stream = response.getOutputStream(); Document document = new Document(); PdfWriter.getInstance(document, stream); document.open(); document.add(data); document.close(); response.setHeader("Expires", "0"); response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0"); response.setContentType("application/pdf"); //This doesn't seem to take effect, oh well response.setHeader("Content-Disposition", "attachment; filename=\"" + documentName + ".pdf\""); Log.Info("Exported pdf - " + documentName); } catch (Exception e) { response.setContentType("text/html"); response.getWriter().write("Error processing pdf: " + e.getLocalizedMessage()); Log.Error("Error processing pdf!",e); } } private Element getMouseListPdf(HttpServletRequest request) throws Exception { int holderID = stringToInt(request.getParameter("holder_id")); int geneID = stringToInt(request.getParameter("geneID")); int mouseTypeID = stringToInt(request.getParameter("mousetype_id")); int creOnly = stringToInt(request.getParameter("creonly")); int facilityID = stringToInt(request.getParameter("facility_id")); int offset = -1; int limit = -1; String orderBy = request.getParameter("orderby"); String searchTerms = request.getParameter("searchterms"); String status = request.getParameter("status"); if (orderBy == null || orderBy.isEmpty()) { orderBy = "mouse.name"; } if(status == null) { status = "all"; } if (status == "all" && !request.isUserInRole("administrator")) { throw new Exception("You must be an administrator to view all mouse records"); } if(creOnly < 0){ creOnly = 0; } Holder holder = DBConnect.getHolder(holderID); Gene gene = DBConnect.getGene(geneID); Facility facility = DBConnect.getFacility(facilityID); ArrayList<MouseRecord> mice = DBConnect.getMouseRecords(mouseTypeID, orderBy, holderID, geneID, status, searchTerms, false, creOnly, facilityID,limit,offset); ArrayList<MouseType> mouseTypes = DBConnect.getMouseTypes(); String mouseTypeStr = "Listing"; String mouseCountStr = ""; if(mouseTypeID != -1) { for(MouseType type : mouseTypes) { if(type.getMouseTypeID() == mouseTypeID) { mouseTypeStr += " " + type.getTypeName(); break; } } } else { mouseTypeStr += " all"; } mouseCountStr = Integer.toString(mice.size()) + " records total, as of " + new Date().toString(); mouseTypeStr += " records"; if (facility != null) { mouseTypeStr += " in facility " + facility.getFacilityName(); } if (holder != null) { mouseTypeStr += " held by " + holder.getFullname(); } else if(gene != null) { mouseTypeStr += " with gene " + gene.getSymbol() + " " + gene.getFullname(); } if(creOnly > 0) { mouseTypeStr += " with expressed sequence type CRE"; } if(searchTerms != null && !searchTerms.isEmpty()) { mouseTypeStr += " matching search term '" + searchTerms + "'"; } if(!status.equals("live") && !status.equals("all") && request.isUserInRole("administrator")) { mouseTypeStr += " with status='" + status + "'"; } PdfPTable table = new PdfPTable(2); table.setWidthPercentage(100); table.setWidths(new int[]{1,5}); for(MouseRecord mouse : mice){ PdfPCell left = cell(getMouseNameAndNumber(mouse)); table.addCell(left); PdfPTable subtable = new PdfPTable(2); subtable.setWidths(new int[]{5,4}); subtable.addCell(cell(getMouseCategory(mouse))); int commentRowSpan = mouse.isIS() ? 1 : 2; subtable.addCell(cell(getFormattedMouseComment(mouse.getGeneralComment()),commentRowSpan,1)); if (!mouse.isIS()){ subtable.addCell(cell(getMouseDetails(mouse))); } subtable.addCell(cell(getHolderList(mouse),1,2)); PdfPCell right = new PdfPCell(subtable); right.setBorder(Rectangle.NO_BORDER); table.addCell(right); } Phrase list = phr(); documentName = mouseTypeStr; list.add(phr(mouseTypeStr,FONT_TITLE)); list.add(NL); list.add(phr(mouseCountStr,FONT_BOLD)); list.add(table); return list; } private static PdfPCell cell(Phrase phr){ return cell(phr, 1,1); } private static PdfPCell cell(Phrase phr, int rowSpan, int colSpan){ PdfPCell cell = new PdfPCell(phr); cell.setRowspan(rowSpan); cell.setColspan(colSpan); cell.setPaddingLeft(3); cell.setPaddingRight(1); cell.setPaddingBottom(4); cell.setPaddingTop(0); cell.setLeading(0f, 1.1f); return cell; } private static Phrase getMouseNameAndNumber(MouseRecord mouse){ Phrase p = phr(); p.add(phr(mouse.getMouseName(), FONT_MOUSENAME)); p.add(NL); p.add(phr("Record #" + mouse.getMouseID())); return p; } private static Phrase getMouseCategory(MouseRecord mouse){ Phrase p = phr(); p.add(phrb(mouse.getMouseType())); if (mouse.getGeneID() != null) { p.add(NL); p.add(formatGenePdf(mouse.getGeneSymbol(),mouse.getGeneName(),mouse.getGeneID())); } if (mouse.isMA() && mouse.getModificationType() != null) { p.add(NL); p.add(phrb("Modification Type: ")); p.add(phr(mouse.getModificationType())); } if (mouse.getExpressedSequence() != null) { p.add(NL); p.add(getExpressedSequence(mouse)); } if (mouse.getRegulatoryElement() != null) { p.add(NL); p.add(phrb("Regulatory Element:")); p.add(phr(" " + mouse.getRegulatoryElement())); } if (mouse.isIS()) { p.add(NL); p.add(phrb("Supplier and catalog #:")); String source = mouse.getSource(); source = source.replaceAll("\\|\\|", ", "); p.add(phr(" " + source)); } return p; } private static Phrase getMouseDetails(MouseRecord mouse){ Phrase p = phr(); if (mouse.isTG() || mouse.isMA()) { Phrase source; if (mouse.getSource() == null || mouse.getSource().equals("")) { source = phr("none"); } else { source = formatSymbolPdf(mouse.getSource()); } String repositoryCatalogNumber = mouse.getRepositoryCatalogNumber(); if (repositoryCatalogNumber == null || repositoryCatalogNumber.equals("") || repositoryCatalogNumber.equals("null")) { repositoryCatalogNumber = "none"; } p.add(phr("Official Symbol: ")); p.add(source); String officialName = mouse.getOfficialMouseName(); if (officialName != null && !officialName.isEmpty()) { p.add(NL); p.add(phr(officialName)); } p.add(NL); p.add(phr("MGI: " + repositoryCatalogNumber)); if (mouse.getPubmedIDs() == null || mouse.getPubmedIDs().isEmpty()) { p.add(NL); p.add(phr("Unpublished")); } else { String allIDs = ""; boolean first = true; boolean hasValidPmIds = false; for (String pmid : mouse.getPubmedIDs()) { if (!first) allIDs += ", "; if (pmid != null && !pmid.isEmpty()) hasValidPmIds = true; first = false; allIDs += pmid; } if (hasValidPmIds){ p.add(NL); p.add(phr("PubMed: " + allIDs)); } } if (mouse.getBackgroundStrain() != null && !mouse.getBackgroundStrain().isEmpty()) { p.add(NL); p.add(phr("Background Strain: " + mouse.getBackgroundStrain())); } if (mouse.getMtaRequired() != null) { if (mouse.getMtaRequired().equalsIgnoreCase("Y")) { // table.append("<dt>MTA is required.</dt>\r\n"); } else if (mouse.getMtaRequired().equalsIgnoreCase("D")) { // table.append("<dt>Unknown if MTA required.</dt>\r\n"); } else if (mouse.getMtaRequired().equalsIgnoreCase("N")) { // table.append("<dt>MTA is not required</dt>\r\n"); } } if (mouse.getGensat() != null && !mouse.getGensat().isEmpty()) { p.add(NL); p.add(phr("Gensat founder line: " + mouse.getGensat())); } } if (mouse.isCryoOnly()) { p.add(NL); p.add(phrb("Cryopreserved only")); } if (mouse.getCryopreserved() != null && mouse.getCryopreserved().equalsIgnoreCase("Y")) { p.add(NL); p.add(phrb("Cryopreserved only")); } // if (mouse.isEndangered()) { // table.append("<dt><span class='endangered'>Endangered</span></dt>\r\n"); // } return p; } private static Phrase getHolderList(MouseRecord mouse) { Phrase p = phr("Holders: "); Boolean first = true; for (MouseHolder holder : mouse.getHolders()) { if (holder.isCovert()) { continue; } if (holder.getFirstname() == null && holder.getLastname() == null) { continue; } String cryoLiveStatus = ""; if (holder.getCryoLiveStatus() != null) { // NULL = ignore // Live = live only // LiveCryo = live and cryo // Cryo = cryo only if (holder.getCryoLiveStatus().equalsIgnoreCase("Live only")) { cryoLiveStatus = ""; } else if (holder.getCryoLiveStatus().equalsIgnoreCase("Live and cryo")) { cryoLiveStatus = "(Cryo,Live)"; } else if (holder.getCryoLiveStatus().equalsIgnoreCase("Cryo only")) { cryoLiveStatus = "(Cryo)"; } } String facilityName = holder.getFacilityID() == 1 ? " " : "(" + holder.getFacilityName() + ")"; String firstInitial = ""; if (holder.getFirstname() != null) { firstInitial = holder.getFirstname().substring(0, 1)+ ". "; } if (!first){ p.add(phr(", ")); } else { first = false; } p.add(phr(firstInitial + holder.getLastname() + " " + facilityName + cryoLiveStatus)); } return p; } private static Phrase getExpressedSequence(MouseRecord mouse) { Phrase p = phr(); p.add(phrb("Expressed Sequence: ")); if (mouse.getExpressedSequence() != null) { if (mouse.getExpressedSequence().equalsIgnoreCase("mouse gene") || mouse.getExpressedSequence().equalsIgnoreCase("Mouse Gene (unmodified)")) { p.add(formatGenePdf(mouse.getTargetGeneSymbol(), mouse.getTargetGeneName(), mouse.getTargetGeneID())); } else if (mouse.getExpressedSequence().equalsIgnoreCase("reporter")) { p.add(phr(mouse.getReporter())); } else if (mouse.getExpressedSequence().equalsIgnoreCase("other")|| mouse.getExpressedSequence().equalsIgnoreCase("Modified mouse gene or Other")) { p.add(phr(mouse.getOtherComment())); } else { p.add(phr(mouse.getExpressedSequence())); } } return p; } private static Phrase getFormattedMouseComment(String comment) throws IOException { // hi there [URL]http://asdfasdfasdf[/URL] - > hi there http://asdfasdfasdf // some comments *an important comment in bold* and some more Phrase p = phr(); if (comment == null) return p; String htmlComment = HTMLUtilities.getCommentForDisplay(comment); HashMap<String,Object> map = new HashMap<String,Object>(); map.put("font_factory",new MouseFontFactory()); java.util.List<Element> objects = HTMLWorker.parseToList(new StringReader(htmlComment), null, map); for (Element element : objects) p.add(element); return p; } private static Phrase phr(){ return phr(""); } private static Phrase phr(String text){ return phr(text, FONT_NORMAL); } private static Phrase phrb(String text){ return phr(text, FONT_BOLD); } private static Phrase phr(String text, Font font){ return new Phrase(text, font); } private static Phrase formatGenePdf(String symbol, String name, String id){ Phrase gene = phr(" "); gene.add(phrb(symbol)); gene.add(phr(" - " + name)); gene.add(NL); gene.add(phr(" MGI: " + id)); return gene; } private static Phrase formatSymbolPdf(String symbol) { Phrase p = phrb(symbol); //TODO parse and set the rise for the chunk in brackets return p; } public static class MouseFontFactory implements FontProvider { public Font getFont(String fontname, String encoding, boolean embedded, float size, int style, BaseColor color) { return new Font(FONT_NORMAL.getFamily(), FONT_NORMAL.getSize(), style, color); } public boolean isRegistered(String fontname) { return false; } } }